Newton Developer Technical Support Sample Code
Locale Samples  -  "24 Hour" & "lower case"
by Henry Cate for Newton Developer Technical Support
Copyright  1996 by Apple Computer, Inc.  All rights reserved.

You may incorporate this sample code into your applications without
restriction.  This sample code has been provided "AS IS" and the
responsibility for its operation is 100% yours.  You are not permitted to
modify and redistribute the source as "DTS Sample Code." If you are going
to re-distribute the source, we require that you make it clear in the
source that the code was descended from Apple-provided sample code, but
that you've made changes.


The sample illustrates how to change the Newton  OS Locale Bundle.
The new locale makes the Newton  PDA use a 24 hour clock, and changes 
the days of the week & months of the year to appear in lower case.

This sample was done as an auto part, so the InstallScript is not
EnsuredInternal'd.  If you want an Application to create and add a  
locale at install time, you can make two methods as part of the base,  
then the InstallScript & RemoveScript will each call one of the   
methods.  This will save some space in the internal heap.  Note the  
remove locale method you define as part of the base will have to be 
ensured internal in the InstallScript.

Check the "Localizing Newton Applications" in the Newton Programmer's 
Guide for more information about locales.  For more information about 
how to handle the card  being pulled problem read the article "Newton 
still needs the card you removed."

Be aware that changing the day and time formats can affect how the 
system parses the string.  So if you change one of these formats, make 
sure you use the correct dictionary in the built in locales.


Here are some points to be aware of:

1) Currently NTK 1.6 has trouble down loading the "lower case" package 
a second time, ie when it already exists on the Newton  PDA.  We are 
investigating this problem.  For now delete the package on the 
Newton  PDA before down loading the new version.

2) These samples will not run on 1.x Newton OS.  Overriding any of the 
following slots in a locale bundle can generate errors:

  - days of week (long, abbr, terse or short);
  - month names (long, abbr, terse or short);
  - decimal point
  - group separator (i.e. the thousand separator)
  - negative number prefix
  - nagative number suffix
  - currency prefix
  - currency suffix

Typically the Newton will work for a little while, and then the user 
will get a message about one of the above slots in the locale bundle, 
or the Newton will generate bus errors.  These bus errors will be 
usually  indicated in error dialogs by large positive error numbers.   
The problem occurs because objects can move around in the NewtonScript 
heap, and the 1.x OS does not respond properly when this happens 
with locale information.

You can work around this problem by making sure that the contents of 
all the slots in your locale frame reside in your package and not in 
the NewtonScript heap.  Strings are normally created using the string 
literal statement ("somestring") so they reside in your package.  With 
an array or frame, you must be careful to avoid using the normal array 
or frame constructor statement ([] or {}) which generates a new array 
or frame in the NewtonScript heap.  Instead, you can use the syntax 
for an array or frame literal ('[] or '{}) to ensure that the frame 
resides in your package.  You could also create a build-time constant 
for the frame or array and reference the constant in your locale frame.  
(See p 1-9 of the NewtonScript Reference manual for more information 
on array and frame literals.)

Below is a locale sample which should work, but doesn't in the Newton 
1.x OS.  To illustrate the basic principle we'll just change the short 
version of the day of the week to lower case and make the decimal point 
an asterisk.

local usLocaleBundle := call kFindLocaleFunc with ("U.S.");
local usLongProto := usLocaleBundle.longDateFormat;
local myLocaleBundle := {
	_proto: usLocaleBundle,
	title: "lower case US:PIEDTS",
	decimalPoint: "*",
	longDateFormat: {
		_proto: usLongProto,
		shortDofWeek:  ["s","m","t","w","t","f","s"],
		},
	};
call kAddLocalefunc with (myLocaleBundle);
SetLocale (myLocaleBundle.title);

Because the shortDofWeek array is constructed in the NewtonScript heap, 
after awhile it will be moved to some new location in the heap, and 
then a bus error would be generated.

Here is a work around:

local usLocaleBundle := call kFindLocaleFunc with ("U.S.");
local usLongProto := usLocaleBundle.longDateFormat;
local myLocaleBundle := {
	_proto: usLocaleBundle,
	title: "lower case US:PIEDTS",
	// no changes needed for string literals
	decimalPoint: "*",
	longDateFormat: {
		_proto: usLongProto,
		// added single quote to make array literal
		shortDofWeek:  '["s","m","t","w","t","f","s"],
		},
	};
call kAddLocalefunc with (myLocaleBundle);
SetLocale (myLocaleBundle.title);

Note the only change in the new version is the single quote in front 
of the shortDofWeek array.  This single quote says make the array a 
literal, as opposed to dynamically creating the array each time the 
function is executed.  The array will be created when the function 
is compiled, and the same array will be used each time the function 
is executed.

Now when NTK compiles the above function, the array will be created 
and stored in the package.  (If the same code was typed into the 
inspector, the function, and hence the array, will reside the 
NewtonScript heap and so the bus errors will still happen.)  By 
having NTK create the array and store it in the package, the array 
wouldn't be moved around.  This avoids the problem which produces 
the bus error.

Also note because strings are usually created as string literals, the 
new decimalPoint string will be in the package.  So normally the 
strings in the list above wouldn't be a problem, but the developer 
will need to be aware of the potential for trouble with these slots.

Because the data for the locale bundle exists in a package, we have 
to be prepared for the Application being removed or deleted.  To do 
this cleanly we'll need to save the locale bundle being used before 
the new locale is installed, and restore it after the application is 
removed.  Here is a sample of how to do it:

InstallScript := func(partFrame)
begin
        // get current the locale title, and save
        local oldLocale := GetLocale ();
        partFrame.oldLocaleTitle := oldLocale.title;
        call partFrame.theForm.RegisterLocale with ();
end;

RemoveScript :=  func(partFrame)
begin
   // restore old locale
   SetLocale(partFrame.oldLocaleTitle);
   call kRemoveLocaleFunc with ("lower case US:PIEDTS");
end;

Notice in the InstallScript we make a call to a RegisterLocale function 
in the base view of the application.  The RegisterLocale function would 
contain the example locale-replacement code in the first example.  We do 
this because for form parts (applications) the system does an 
EnsureInternal on the InstallScript before it is called.  This 
duplicates the entire function (including strings, frames, and arrays 
used in that function) into the NS heap.

To work around this, we move the function that adds the locale (and 
contains the new locale bundle) to a slot in theForm, which is the 
template for the application's base view and which does not get 
EnsureInternal'd, and then we call that function.  (Another workaround 
might be to put the template for the locale bundle itself in the base 
view and have the installScript clone that template, set the _proto 
slots appropriately, and then register and set the locale bundle.


